<?php defined('SYSPATH') or die('Access error!');

abstract class Core_Image {

	// 剪切使用的常量
	const NONE    = 0x01;
	const WIDTH   = 0x02;
	const HEIGHT  = 0x03;
	const AUTO    = 0x04;
	const INVERSE = 0x05;

	const HORIZONTAL = 0x11;
	const VERTICAL   = 0x12;

	public static $default_driver = 'GD';

	protected static $_checked = FALSE;

	public static function factory($file, $driver = NULL)
	{
		if ($driver === NULL)
		{
			$driver = Image::$default_driver;
		}

		$class = 'Image_'.$driver;
		return new $class($file);
	}

	public $file;

	public $width;

	public $height;

	public $type;

	public $mime;

	public function __construct($file)
	{
            
          
		try
		{
			$file = realpath($file);
			$info = getimagesize($file);
                        
                 
		}
		catch (Exception $e)
		{
		}
		if (empty($file) OR empty($info))
		{
			throw new Core_Exception('不是图片文件: :file',
				array(':file' => Core::debug_path($file)));
		}

		$this->file   = $file;
		$this->width  = $info[0];
		$this->height = $info[1];
		$this->type   = $info[2];
		$this->mime   = image_type_to_mime_type($this->type);
	}

	/**
	 *     echo $image;
	 * @return  string
	 */
	public function __toString()
	{
		try
		{
			return $this->render();
		}
		catch (Exception $e)
		{
			if (is_object(Core::$log))
			{
				$error = Core::exception_text($e);

				Core::$log->add(Core::ERROR, $error);
			}

			return '';
		}
	}

	/**
	 *    图片缩放
	 *
	 *     $image->resize(200, 200);
	 *
	 *     $image->resize(200, 200, Image::INVERSE);
	 *
	 *     $image->resize(500, NULL);
	 *
	 *     $image->resize(NULL, 500);
	 *
	 *     $image->resize(200, 500, Image::NONE);
	 *
	 * @param   integer  
	 * @param   integer  
	 * @param   integer 
	 * @return  $this
	 * @uses    Image::_do_resize
	 */
	public function resize($width = NULL, $height = NULL, $master = NULL)
	{
		if ($master === NULL)
		{
			$master = Image::AUTO;
		}
		elseif ($master == Image::WIDTH AND ! empty($width))
		{
			$master = Image::AUTO;

			$height = NULL;
		}
		elseif ($master == Image::HEIGHT AND ! empty($height))
		{
			$master = Image::AUTO;

			$width = NULL;
		}

		if (empty($width))
		{
			if ($master === Image::NONE)
			{
				$width = $this->width;
			}
			else
			{
				$master = Image::HEIGHT;
			}
		}

		if (empty($height))
		{
			if ($master === Image::NONE)
			{
				$height = $this->height;
			}
			else
			{
				$master = Image::WIDTH;
			}
		}

		switch ($master)
		{
			case Image::AUTO:
				$master = ($this->width / $width) > ($this->height / $height) ? Image::WIDTH : Image::HEIGHT;
			break;
			case Image::INVERSE:
				$master = ($this->width / $width) > ($this->height / $height) ? Image::HEIGHT : Image::WIDTH;
			break;
		}

		switch ($master)
		{
			case Image::WIDTH:
				$height = $this->height * $width / $this->width;
			break;
			case Image::HEIGHT:
				$width = $this->width * $height / $this->height;
			break;
		}

		$width  = max(round($width), 1);
		$height = max(round($height), 1);

		$this->_do_resize($width, $height);

		return $this;
	}

	/**
	 *  剪切图片
	 *
	 *     $image->crop(200, 200);
	 *
	 * @param   integer  
	 * @param   integer 
	 * @param   mixed   
	 * @param   mixed   
	 * @return  $this
	 * @uses    Image::_do_crop
	 */
	public function crop($width, $height, $offset_x = NULL, $offset_y = NULL)
	{
		if ($width > $this->width)
		{
			$width = $this->width;
		}

		if ($height > $this->height)
		{
			$height = $this->height;
		}

		if ($offset_x === NULL)
		{
			$offset_x = round(($this->width - $width) / 2);
		}
		elseif ($offset_x === TRUE)
		{
			$offset_x = $this->width - $width;
		}
		elseif ($offset_x < 0)
		{
			$offset_x = $this->width - $width + $offset_x;
		}

		if ($offset_y === NULL)
		{
			$offset_y = round(($this->height - $height) / 2);
		}
		elseif ($offset_y === TRUE)
		{
			$offset_y = $this->height - $height;
		}
		elseif ($offset_y < 0)
		{
			$offset_y = $this->height - $height + $offset_y;
		}

		$max_width  = $this->width  - $offset_x;
		$max_height = $this->height - $offset_y;

		if ($width > $max_width)
		{
			$width = $max_width;
		}

		if ($height > $max_height)
		{
			$height = $max_height;
		}

		$this->_do_crop($width, $height, $offset_x, $offset_y);

		return $this;
	}

	/**
	 *  按比例缩小放大
	 *     $image->rotate(45);
	 *     $image->rotate(-90);
	 * @param   integer 
	 * @return  $this
	 * @uses    Image::_do_rotate
	 */
	public function rotate($degrees)
	{
		$degrees = (int) $degrees;

		if ($degrees > 180)
		{
			do
			{
				$degrees -= 360;
			}
			while($degrees > 180);
		}

		if ($degrees < -180)
		{
			do
			{
				$degrees += 360;
			}
			while($degrees < -180);
		}

		$this->_do_rotate($degrees);

		return $this;
	}

	/**
	 * 翻转的图像沿水平或垂直轴。
	 *
	 *     $image->flip(Image::HORIZONTAL);
	 *
	 *     $image->flip(Image::VERTICAL);
	 *
	 * @param   integer 
	 * @return  $this
	 * @uses    Image::_do_flip
	 */
	public function flip($direction)
	{
		if ($direction !== Image::HORIZONTAL)
		{
			$direction = Image::VERTICAL;
		}

		$this->_do_flip($direction);

		return $this;
	}

	/**
	 * 一个给定的量，以使图像。
	 *
	 *     $image->sharpen(20);
	 *
	 * @param   integer 
	 * @return  $this
	 * @uses    Image::_do_sharpen
	 */
	public function sharpen($amount)
	{
		$amount = min(max($amount, 1), 100);

		$this->_do_sharpen($amount);

		return $this;
	}

	/**
	 * 图片透明度处理
	 *
	 *     $image->reflection(50);
	 *
	 *     $image->reflection(50, 100, TRUE);
	 *
	 *     $image->reflection(50, 60, TRUE);
	 *
	 * @param   integer   
	 * @param   integer  
	 * @param   boolean   
	 * @return  $this
	 * @uses    Image::_do_reflection
	 */
	public function reflection($height = NULL, $opacity = 100, $fade_in = FALSE)
	{
		if ($height === NULL OR $height > $this->height)
		{
			$height = $this->height;
		}

		$opacity = min(max($opacity, 0), 100);

		$this->_do_reflection($height, $opacity, $fade_in);

		return $this;
	}

	/**
	 * 添加水印
	 *
	 *     $mark = Image::factory('upload/watermark.png');
	 *     $image->watermark($mark, TRUE, TRUE);
	 *
	 * @param   object   watermark Image instance
	 * @param   integer  offset from the left
	 * @param   integer  offset from the top
	 * @param   integer  opacity of watermark: 1-100
	 * @return  $this
	 * @uses    Image::_do_watermark
	 */
	public function watermark(Image $watermark, $offset_x = NULL, $offset_y = NULL, $opacity = 100)
	{
		if ($offset_x === NULL)
		{
			$offset_x = round(($this->width - $watermark->width) / 2);
		}
		elseif ($offset_x === TRUE)
		{
			$offset_x = $this->width - $watermark->width;
		}
		elseif ($offset_x < 0)
		{
			$offset_x = $this->width - $watermark->width + $offset_x;
		}

		if ($offset_y === NULL)
		{
			$offset_y = round(($this->height - $watermark->height) / 2);
		}
		elseif ($offset_y === TRUE)
		{
			$offset_y = $this->height - $watermark->height;
		}
		elseif ($offset_y < 0)
		{
			$offset_y = $this->height - $watermark->height + $offset_y;
		}
		$opacity = min(max($opacity, 1), 100);
		$this->_do_watermark($watermark, $offset_x, $offset_y, $opacity);
		return $this;
	}

	/**
	 * 设置图片的背景色
	 *
	 *     $image->background('#000');
	 *
	 *     $image->background('#000', 50);
	 *
	 * @param   string   hexadecimal color value
	 * @param   integer  background opacity: 0-100
	 * @return  $this
	 * @uses    Image::_do_background
	 */
	public function background($color, $opacity = 100)
	{
		if ($color[0] === '#')
		{
			$color = substr($color, 1);
		}

		if (strlen($color) === 3)
		{
			$color = preg_replace('/./', '$0$0', $color);
		}

		list ($r, $g, $b) = array_map('hexdec', str_split($color, 2));

		$opacity = min(max($opacity, 0), 100);

		$this->_do_background($r, $g, $b, $opacity);

		return $this;
	}

	/**
	 * 保存图片
	 *
	 *     $image->save('saved/cool.png');
	 *     $image->save();
	 * @param   string   new image path
	 * @param   integer  quality of image: 1-100
	 * @return  boolean
	 * @uses    Image::_save
	 * @throws  Core_Exception
	 */
	public function save($file = NULL, $quality = 100)
	{
		if ($file === NULL)
		{
			$file = $this->file;
		}

		if (is_file($file))
		{
			if ( ! is_writable($file))
			{
				throw new Core_Exception('图片必须可写: :file',
					array(':file' => Core::debug_path($file)));
			}
		}
		else
		{
			$directory = realpath(pathinfo($file, PATHINFO_DIRNAME));

			if ( ! is_dir($directory) OR ! is_writable($directory))
			{
				throw new Core_Exception('目录必须可写: :directory',
					array(':directory' => Core::debug_path($directory)));
			}
		}

		$quality = min(max($quality, 1), 100);

		return $this->_do_save($file, $quality);
	}

	/**
	 * 渲染图像，并返回二进制字符串。
	 *
	 *     $data = $image->render(NULL, 50);
	 *
	 *     $data = $image->render('png');
	 *
	 * @param   string   图片类型: png, jpg, gif, etc
	 * @param   integer  图片质量: 1-100
	 * @return  string
	 * @uses    Image::_do_render
	 */
	public function render($type = NULL, $quality = 100)
	{
		if ($type === NULL)
		{
			$type = image_type_to_extension($this->type, FALSE);
		}

		return $this->_do_render($type, $quality);
	}

	abstract protected function _do_resize($width, $height);

	abstract protected function _do_crop($width, $height, $offset_x, $offset_y);

	abstract protected function _do_rotate($degrees);

	abstract protected function _do_flip($direction);

	abstract protected function _do_sharpen($amount);

	abstract protected function _do_reflection($height, $opacity, $fade_in);

	abstract protected function _do_watermark(Image $image, $offset_x, $offset_y, $opacity);

	abstract protected function _do_background($r, $g, $b, $opacity);

	abstract protected function _do_save($file, $quality);

	abstract protected function _do_render($type, $quality);

}
